package com.example.palette.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Random;

public class CustomRectangleView extends View {
    private int mSingleLineNumber = 50;
    private int mLineNumber = 4;
    private int mColorE8E3E3 = Color.parseColor("#E8E3E3");
    private int mColorFFFFFF = Color.parseColor("#FFFFFF");
    private int mColor000000 = Color.parseColor("#000000");
    private float mMarginHorizontal = dp2px(5f);
    private float mBigMarginVertical = dp2px(15f);
    private float mSmallMarginVertical = dp2px(5f);
    private float mTextPaddingVertical = dp2px(2f);
    private float mTextBigPaddingHorizontal = dp2px(20f);
    private float mTextSmallPaddingHorizontal = dp2px(2f);
    private float mTextSize = sp2px(15f);
    private float mTextBgWidth = 0f;
    private float mTextBgHeight = 0f;
    private float mRectangleWidth = 0f;
    private float mRectangleHeight = 0f;
    private float mCurrentScale = 1f;
    private Rect mCurrentScaleRect = new Rect();
    private float mScaleTranslateX = 0f;
    private float mScaleTranslateY = 0f;
    private float mTranslateX = 0f;
    private float mTranslateY = 0f;
    private float mMinScale = 0.8f;
    private float mMaxScale = 4f;
    private boolean mDrawBorderLine = true;
    private Paint mTextBgPaint = new Paint();
    private Paint mSmallRectangleBgPaint = new Paint();
    private Paint mSmallRectangleDataPaint = new Paint();
    private Paint mMarkerRectPaint = new Paint();
    private Paint mMarkerLinePaint = new Paint();
    private TextPaint mMarkerTextPaint = new TextPaint();
    private RectF mMarkerRectF = new RectF();
    private Rect mTextRect = new Rect();
    private String[] mTextArray = new String[]{"左","中1","中2","右"};
    private ScaleGestureDetector mScaleGestureDetector;
    private GestureDetector mGestureDetector;
    private List<RectF> mSmallRectangleList = new ArrayList<>();
    private List<Double> mPressureList = new ArrayList<>();
    private int mSelectedMarkerIndex = -1;
    private AreaIndex mSingleAreaRectFIndex = new AreaIndex(-1,-1,-1,-1,-1);
    private List<Integer> mSingleAreaIndexList = new ArrayList<>();
    private List<AreaIndex> mMultipleAreaRectFIndexList = new ArrayList<>();
    private List<List<Integer>> mMultipleAreaIndexRangeList = new ArrayList<>();
    private List<RectF> mFilterAreaRectFList = new ArrayList<>();
    private List<List<Integer>> mFilterAreaIndexRangeList = new ArrayList<>();
    private List<Integer> mFilterAreaIndexList = new ArrayList<>();
    private SingleTapUpListener mSingleTapUpListener;
    private TrackListener mTrackListener;
    private ColorMatcher mColorMatcher;

    public CustomRectangleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mScaleGestureDetector = new ScaleGestureDetector(context,new SDGListener());
        mGestureDetector = new GestureDetector(context,new GDListener());
        mTextBgPaint.setAntiAlias(true);
        mTextBgPaint.setStyle(Paint.Style.FILL);
        mTextBgPaint.setTextSize(mTextSize);
        mTextBgPaint.getTextBounds(mTextArray[1],0,mTextArray[1].length(),mTextRect);
        mSmallRectangleBgPaint.setAntiAlias(true);
        mSmallRectangleBgPaint.setColor(mColorE8E3E3);
        mSmallRectangleBgPaint.setStyle(Paint.Style.STROKE);
        mSmallRectangleDataPaint.setAntiAlias(true);
        mSmallRectangleDataPaint.setStyle(Paint.Style.FILL);
        mMarkerRectPaint.setAntiAlias(true);
        mMarkerRectPaint.setStrokeWidth(3f);
        mMarkerRectPaint.setStyle(Paint.Style.STROKE);
        mMarkerRectPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
        mMarkerLinePaint.setAntiAlias(true);
        mMarkerLinePaint.setColor(Color.BLACK);
        mMarkerLinePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
        mMarkerTextPaint.setAntiAlias(true);
        mMarkerTextPaint.setColor(Color.WHITE);
        mMarkerTextPaint.setTextSize(sp2px(12f));
        mTextBgHeight = mTextRect.bottom - mTextRect.top + 2 * mTextPaddingVertical;
        mTextBgWidth = mTextRect.right - mTextRect.left + mTextBigPaddingHorizontal + mTextSmallPaddingHorizontal;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        mRectangleWidth = (width - mMarginHorizontal * 2) / (float) mSingleLineNumber;
        mRectangleHeight = (height - (mLineNumber + 1) * mBigMarginVertical - mLineNumber * (mSmallMarginVertical + mTextBgHeight)) / (float) mLineNumber;
        setMeasuredDimension(width,height);
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onDraw(Canvas canvas) {
        mSmallRectangleList.clear();
        mFilterAreaIndexList.clear();
        mFilterAreaIndexList.addAll(generateFilterIndexList());
        canvas.drawColor(mColorE8E3E3);
        canvas.getClipBounds(mCurrentScaleRect);
        canvas.translate(mScaleTranslateX,mScaleTranslateY);
        canvas.translate(-mTranslateX,-mTranslateY);
        float left = mMarginHorizontal * mCurrentScale;
        float top = mBigMarginVertical * mCurrentScale + mTextBgHeight * mCurrentScale + mSmallMarginVertical * mCurrentScale;
        float right = left + mRectangleWidth * mCurrentScale;
        float bottom = top + mRectangleHeight * mCurrentScale;
        for (int i = 0; i < mLineNumber; i++) {
            mTextBgPaint.setColor(mColorFFFFFF);
            canvas.drawRect(0f,top - mTextBgHeight * mCurrentScale - mSmallMarginVertical * mCurrentScale,
                            mTextBgWidth * mCurrentScale,top - mSmallMarginVertical * mCurrentScale,mTextBgPaint);
            mTextBgPaint.setColor(mColor000000);
            mTextBgPaint.setTextSize(mTextSize * mCurrentScale);
            canvas.drawText(mTextArray[i],mTextBgWidth * mCurrentScale / 2f - mTextRect.width() * mCurrentScale / 2f,
                            top - mTextBgHeight * mCurrentScale - mSmallMarginVertical * mCurrentScale + mTextRect.height() * mCurrentScale,mTextBgPaint);
            mTextBgPaint.setColor(mColorFFFFFF);
            for (int j = 0; j < mSingleLineNumber; j++) {
                int index = i * mSingleLineNumber + j;
                RectF item = new RectF(left,top,right,bottom);
                canvas.drawRect(item,mTextBgPaint);
                mSmallRectangleList.add(item);
                if(mDrawBorderLine){
                    canvas.drawRect(item,mSmallRectangleBgPaint);
                }
                if(!mFilterAreaIndexList.contains(index) && !mPressureList.isEmpty() && mColorMatcher != null){
                    Double pressure = mPressureList.get(index);
                    mSmallRectangleDataPaint.setColor(mColorMatcher.match(pressure));
                    canvas.drawRect(item,mSmallRectangleDataPaint);
                }
                left = right;
                right = left + mRectangleWidth * mCurrentScale;
            }
            if(!mDrawBorderLine && mPressureList.isEmpty()){
                canvas.drawRect(mMarginHorizontal * mCurrentScale,top,mSingleLineNumber * mRectangleWidth * mCurrentScale,bottom,mTextBgPaint);
            }
            left = mMarginHorizontal * mCurrentScale;
            top = bottom + mBigMarginVertical * mCurrentScale + mTextBgHeight * mCurrentScale + mSmallMarginVertical * mCurrentScale;
            right = left + mRectangleWidth * mCurrentScale;
            bottom = top + mRectangleHeight * mCurrentScale;
        }
        drawSingleAreaRectF(mSingleAreaRectFIndex,mSingleAreaIndexList,canvas);
        drawMultipleAreaRectF(canvas);
        drawMarkInfo(mSelectedMarkerIndex,canvas);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mScaleGestureDetector.onTouchEvent(event);
        mGestureDetector.onTouchEvent(event);
        return true;
    }

    public void setDrawBorderLine(boolean draw){
        mDrawBorderLine = draw;
    }

    public void cancelSingleArea(){
        mSingleAreaRectFIndex.setEmpty();
        mSingleAreaIndexList.clear();
        invalidate();
    }

    public void cancelMultipleArea(boolean all){
        if (all) {
            mMultipleAreaRectFIndexList.clear();
            mMultipleAreaIndexRangeList.clear();
        } else {
            int size = mMultipleAreaRectFIndexList.size();
            if (size > 0) {
                mMultipleAreaRectFIndexList.remove(size - 1);
                mMultipleAreaIndexRangeList.remove(size - 1);
            }
        }
        invalidate();
    }

    public void zoom(boolean bigger){
        if(bigger){
            mCurrentScale *= 1.2f;
        }else {
            mCurrentScale *= 0.8f;
        }
        if(mCurrentScale > mMaxScale){
            mCurrentScale = mMaxScale;
        }
        if(mCurrentScale < mMinScale){
            mCurrentScale = mMinScale;
        }
        mScaleTranslateX = mCurrentScaleRect.centerX() * (1f - mCurrentScale);
        mScaleTranslateY = mCurrentScaleRect.centerY() * (1f - mCurrentScale);
        invalidate();
    }

    public void addFilterRectF(List<RectF> rectFList){
        mFilterAreaIndexRangeList.clear();
        mFilterAreaRectFList.clear();
        mFilterAreaRectFList.addAll(rectFList);
        for(RectF rectF:mFilterAreaRectFList){
            setAreaRectF(rectF,true,true);
        }
        invalidate();
    }

    public void setData(List<Double> data,boolean isTrack){
        if(data.size() == mLineNumber * mSingleLineNumber){
            if(isTrack){
                if(mPressureList.isEmpty()){
                    mPressureList.addAll(data);
                }else {
                    List<Double> result = new ArrayList<>();
                    for (int i = 0; i < mPressureList.size(); i++) {
                        Double src = mPressureList.get(i);
                        Double dest = data.get(i);
                        if(src < dest){
                            result.add(dest);
                        }else {
                            result.add(src);
                        }
                    }
                    mPressureList = result;
                    if(mTrackListener != null){
                        mTrackListener.onTrack(mPressureList);
                    }
                }
            }else {
                mPressureList.clear();
                mPressureList.addAll(data);
            }
            invalidate();
        }
    }

    public boolean isAreaSelectNotEmpty(boolean isSingle,boolean isFilter){
        if(isFilter){
            return !mFilterAreaIndexRangeList.isEmpty();
        }else {
            if(isSingle){
                return !mSingleAreaIndexList.isEmpty();
            }else {
                return !mMultipleAreaIndexRangeList.isEmpty();
            }
        }
    }

    public void resetZoom(){
        mCurrentScale = 1f;
        mCurrentScaleRect.setEmpty();
        mScaleTranslateX = 0f;
        mScaleTranslateY = 0f;
        mTranslateX = 0f;
        mTranslateY = 0f;
        invalidate();
    }

    public void resetAll() {
        mPressureList.clear();
        mSelectedMarkerIndex = -1;
        mFilterAreaRectFList.clear();
        mFilterAreaIndexRangeList.clear();
        mSingleAreaRectFIndex.setEmpty();
        mSingleAreaIndexList.clear();
        mMultipleAreaRectFIndexList.clear();
        mMultipleAreaIndexRangeList.clear();
        mCurrentScale = 1f;
        mCurrentScaleRect.setEmpty();
        mScaleTranslateX = 0f;
        mScaleTranslateY = 0f;
        mTranslateX = 0f;
        mTranslateY = 0f;
        invalidate();
    }

    public void setAreaRectF(RectF rectF,boolean single,boolean filter){
        Float left = null;
        Float right = null;
        Float top = null;
        Float bottom = null;
        int leftIndex = -1;
        int rightIndex = -1;
        int topIndex = -1;
        int bottomIndex = -1;
        List<Integer> indexList = new ArrayList<>();
        for (int i = 0; i < mSmallRectangleList.size(); i++) {
            RectF it = mSmallRectangleList.get(i);
            boolean matchX = false;
            boolean matchY = false;
            if(Math.abs(it.centerX() + mScaleTranslateX - mTranslateX - (rectF.centerX() + mScaleTranslateX - mTranslateX)) <= (it.width() + rectF.width()) / 2){
                if(left == null || it.left + mScaleTranslateX - mTranslateX <= left){
                    left = it.left + mScaleTranslateX - mTranslateX;
                    leftIndex = i;
                    matchX = true;
                }
                if(right == null || it.right + mScaleTranslateX - mTranslateX >= right){
                    right = it.right + mScaleTranslateX - mTranslateX;
                    rightIndex = i;
                    matchX = true;
                }
            }
            if(Math.abs(it.centerY() + mScaleTranslateY - mTranslateY - (rectF.centerY() + mScaleTranslateY - mTranslateY)) <= (it.height() + rectF.height()) / 2){
                if(top == null || it.top + mScaleTranslateY - mTranslateY <= top){
                    top = it.top + mScaleTranslateY - mTranslateY;
                    topIndex = i;
                    matchY = true;
                }
                if(bottom == null || it.bottom + mScaleTranslateY - mTranslateY >= bottom){
                    bottom = it.bottom + mScaleTranslateY - mTranslateY;
                    bottomIndex = i;
                    matchY = true;
                }
            }
            if(matchX && matchY){
                indexList.add(i);
            }
        }
        if(filter){
            mFilterAreaIndexRangeList.add(indexList);
        }else {
            if(single){
                mSingleAreaIndexList.clear();
                mSingleAreaIndexList.addAll(indexList);
            }else {
                mMultipleAreaIndexRangeList.add(indexList);
            }
            if(!indexList.isEmpty()){
                if(single){
                    mSingleAreaRectFIndex = new AreaIndex(Color.GREEN,leftIndex,topIndex,rightIndex,bottomIndex);
                }else {
                    Random random = new Random();
                    mMultipleAreaRectFIndexList.add(new AreaIndex(Color.rgb(random.nextInt(256),random.nextInt(256),random.nextInt(256)),leftIndex,topIndex,rightIndex,bottomIndex));
                }
                invalidate();
            }
        }
    }

    private List<Integer> generateFilterIndexList(){
        List<Integer> result = new ArrayList<>();
        for(List<Integer> range:mFilterAreaIndexRangeList){
           result.addAll(generateIndexList(range));
        }
        return result;
    }

    private List<Integer> generateIndexList(List<Integer> range){
        List<Integer> result = new ArrayList<>();
        if(!range.isEmpty()){
            if(range.size() == 1){
                result.add(range.get(0));
            }else {
                if(range.get(1) - range.get(0) == mSingleLineNumber){
                    for(Integer i:range){
                        result.add(i);
                    }
                }else {
                    int group = range.size() / 2;
                    while (group > 0){
                        int start = range.get(group * 2 - 2);
                        int end = range.get(group * 2 - 1);
                        for (int i = start; i <= end ; i++) {
                            result.add(i);
                        }
                        group--;
                    }
                }
            }
        }
        return result;
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private void drawMultipleAreaRectF(Canvas canvas){
        for (int i = 0; i < mMultipleAreaRectFIndexList.size(); i++) {
            AreaIndex areaIndex = mMultipleAreaRectFIndexList.get(i);
            drawSingleAreaRectF(areaIndex,mMultipleAreaIndexRangeList.get(i),canvas);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private void drawSingleAreaRectF(AreaIndex area, List<Integer> indexRange, Canvas canvas){
        if(area.isNotEmpty()){
            List<Integer> indexList = generateIndexList(indexRange);
            mMarkerLinePaint.setStrokeWidth(sp2px(2f));
            mMarkerLinePaint.setColor(area.color);
            mMarkerLinePaint.setStyle(Paint.Style.STROKE);
            mMarkerRectPaint.setColor(area.color);
            mMarkerRectPaint.setStyle(Paint.Style.FILL);
            RectF rectF = new RectF(mSmallRectangleList.get(area.left).left,mSmallRectangleList.get(area.top).top,
                                    mSmallRectangleList.get(area.right).right,mSmallRectangleList.get(area.bottom).bottom);
            canvas.drawRect(rectF,mMarkerLinePaint);
            double totalPressure = 0.0;
            double average = 0.0;
            if(!mPressureList.isEmpty()){
                int time = 0;
                for(Integer i:indexList){
                    if(!mFilterAreaIndexList.contains(i)){
                        double p = mPressureList.get(i);
                        if(p > 0){
                            totalPressure += p;
                            time++;
                        }
                    }
                }
                if(time > 0){
                    average = totalPressure / time;
                }
            }
            String string = String.format(Locale.getDefault(),"平均压力\n%sN",String.format(Locale.getDefault(),"%.2f", average));
            float strWidth = mMarkerTextPaint.measureText(string) / 3 * 2;
            StaticLayout staticLayout = StaticLayout.Builder.obtain(string,0,string.length(),mMarkerTextPaint, (int) strWidth).setAlignment(Layout.Alignment.ALIGN_CENTER).build();
            boolean drawRight = rectF.right + rectF.left < getWidth();
            float left,right;
            float top = rectF.bottom - staticLayout.getHeight() - 10;
            float bottom = rectF.bottom;
            if(drawRight){
                left = rectF.right + 20;
                right = rectF.right + strWidth + 40;
            }else {
                left = rectF.left - strWidth - 40;
                right = rectF.left - 20;
            }
            RectF dest = new RectF(left,top,right,bottom);
            canvas.saveLayerAlpha(dest,127);
            canvas.drawRoundRect(dest,8f,8f,mMarkerRectPaint);
            canvas.restore();
            int i = canvas.save();
            canvas.translate(left + 10f,top + 5f);
            staticLayout.draw(canvas);
            canvas.restoreToCount(i);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private void drawMarkInfo(int selectedIndex, Canvas canvas){
        if(selectedIndex != -1){
            RectF rectF = mSmallRectangleList.get(selectedIndex);
            mMarkerLinePaint.setStrokeWidth(sp2px(1f));
            mMarkerLinePaint.setColor(Color.BLACK);
            mMarkerRectPaint.setColor(Color.BLACK);
            mMarkerRectPaint.setStyle(Paint.Style.STROKE);
            canvas.drawRect(rectF,mMarkerRectPaint);
            int per = mSingleLineNumber * mLineNumber / (mSingleLineNumber / 2) - 1;
            for (int i = per; i >= 0 ; i--) {
                if(selectedIndex >= i * mSingleLineNumber / 2){
                    boolean right = false;
                    boolean top = false;
                    if(i % 2 == 0){
                        right = true;
                    }
                    if(i < mLineNumber){
                        top = true;
                    }
                    int line = selectedIndex / mSingleLineNumber + 1;
                    int row = selectedIndex - (line - 1) * mSingleLineNumber + 1;
                    if(right && top){
                        canvas.drawLine(rectF.right,rectF.bottom,rectF.right + 60,rectF.bottom + 60,mMarkerLinePaint);
                        canvas.drawLine(rectF.right + 60,rectF.bottom + 60,rectF.right + 120,rectF.bottom + 60,mMarkerLinePaint);
                        drawMarker(canvas,selectedIndex,rectF.right + 120,rectF.bottom + 60,line,row,true,true);
                    }else if(right && !top){
                        canvas.drawLine(rectF.right,rectF.top,rectF.right + 60,rectF.top - 60,mMarkerLinePaint);
                        canvas.drawLine(rectF.right + 60,rectF.top - 60,rectF.right + 120,rectF.top - 60,mMarkerLinePaint);
                        drawMarker(canvas,selectedIndex,rectF.right + 120,rectF.top - 60,line,row,true,false);
                    }else if(!right && top){
                        canvas.drawLine(rectF.left,rectF.bottom,rectF.left - 60,rectF.bottom + 60,mMarkerLinePaint);
                        canvas.drawLine(rectF.left - 60,rectF.bottom + 60,rectF.left - 120,rectF.bottom + 60,mMarkerLinePaint);
                        drawMarker(canvas,selectedIndex,rectF.left - 120,rectF.bottom + 60,line,row,false, true);
                    }else {
                        canvas.drawLine(rectF.left,rectF.top,rectF.left - 60,rectF.top - 60,mMarkerLinePaint);
                        canvas.drawLine(rectF.left - 60,rectF.top - 60,rectF.left - 120,rectF.top - 60,mMarkerLinePaint);
                        drawMarker(canvas,selectedIndex,rectF.left - 120,rectF.top - 60,line,row,false,false);
                    }
                    break;
                }
            }
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    private void drawMarker(Canvas canvas, int index, float x, float y, int line , int row, boolean right, boolean top){
        double pressure = 0.0;
        if(!mFilterAreaIndexList.contains(index) && !mPressureList.isEmpty()){
            pressure = mPressureList.get(index);
        }
        String formatPressure = String.format(Locale.getDefault(),"%.2f",pressure);
        if(mSingleTapUpListener != null){
            mSingleTapUpListener.onSingleTapUp(index,formatPressure);
        }
        String string = String.format(Locale.getDefault(),"压力值\n%sN",formatPressure);
        String string2 = String.format(Locale.getDefault(),"坐标\n%s",line+"-"+row);
        float strWidth = mMarkerTextPaint.measureText(string);
        String str = string + "\n\n" + string2;
        StaticLayout staticLayout = StaticLayout.Builder.obtain(str,0,str.length(),mMarkerTextPaint, (int) strWidth).setAlignment(Layout.Alignment.ALIGN_CENTER).build();
        float r;
        float t;
        if(right){
            r = x;
        }else {
            r = x - strWidth;
        }
        if(top){
            t = y + staticLayout.getHeight();
        }else {
            t = y;
        }
        mMarkerRectPaint.setStyle(Paint.Style.FILL);
        mMarkerRectF.left = r;
        mMarkerRectF.top = t - staticLayout.getHeight() - 20;
        mMarkerRectF.right = r + staticLayout.getWidth();
        mMarkerRectF.bottom = t + 20;
        canvas.saveLayerAlpha(mMarkerRectF,120);
        canvas.drawRoundRect(mMarkerRectF,8f,8f,mMarkerRectPaint);
        canvas.restore();
        canvas.drawLine(r + 20,t - staticLayout.getHeight()/2f,
                        r + staticLayout.getWidth() - 20,t - staticLayout.getHeight()/2f,mMarkerTextPaint);
        int i = canvas.save();
        canvas.translate(r,t - staticLayout.getHeight());
        staticLayout.draw(canvas);
        canvas.restoreToCount(i);
    }

    private void drawSelectRectangle(float x, float y){
        if(mMarkerRectF.contains(x - mScaleTranslateX + mTranslateX,y - mScaleTranslateY + mTranslateY)){
            mSelectedMarkerIndex = -1;
            invalidate();
            return;
        }
        for (int i = 0; i < mSmallRectangleList.size(); i++) {
            RectF rectF = mSmallRectangleList.get(i);
            if(rectF.contains(x - mScaleTranslateX + mTranslateX,y - mScaleTranslateY + mTranslateY)){
                if(mSelectedMarkerIndex == i){
                    mSelectedMarkerIndex = -1;
                }else {
                    mSelectedMarkerIndex = i;
                }
                invalidate();
                return;
            }
        }
        mSelectedMarkerIndex = -1;
        invalidate();
    }

    private float dp2px(float dp){
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,getResources().getDisplayMetrics());
    }

    private float sp2px(float sp){
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,sp,getResources().getDisplayMetrics());
    }

    private class AreaIndex{
        int color = -1;
        int left = -1;
        int top = -1;
        int right = -1;
        int bottom = -1;

        public AreaIndex(int color, int left, int top, int right, int bottom) {
            this.color = color;
            this.left = left;
            this.top = top;
            this.right = right;
            this.bottom = bottom;
        }

        public boolean isNotEmpty(){
            return left != -1 && top != -1 && right != -1 && bottom != -1;
        }

        public void setEmpty(){
            left = top = right = bottom = -1;
        }

    }

    public void setColorMatcher(ColorMatcher matcher) {
        mColorMatcher = matcher;
    }

    public void setSingleTapUpListener(SingleTapUpListener listener) {
        mSingleTapUpListener = listener;
    }

    public void setTrackListener(TrackListener listener) {
        mTrackListener = listener;
    }

    public interface SingleTapUpListener{
        void onSingleTapUp(int index,String pressure);
    }

    public interface ColorMatcher{
        int match(double pressure);
    }

    public interface TrackListener{
        void onTrack(List<Double> list);
    }

    private class SDGListener extends ScaleGestureDetector.SimpleOnScaleGestureListener{
        @Override
        public boolean onScale(@NonNull ScaleGestureDetector detector) {
            mCurrentScale *= detector.getScaleFactor();
            if(mCurrentScale > mMaxScale){
                mCurrentScale = mMaxScale;
            }
            if(mCurrentScale < mMinScale){
                mCurrentScale = mMinScale;
            }
            float focusX = detector.getFocusX();
            float focusY = detector.getFocusY();
            mScaleTranslateX = focusX * (1 - mCurrentScale);
            mScaleTranslateY = focusY * (1 - mCurrentScale);
            invalidate();
            return true;
        }
    }

    private class GDListener extends GestureDetector.SimpleOnGestureListener{
        @Override
        public boolean onSingleTapUp(@NonNull MotionEvent e) {
            drawSelectRectangle(e.getX(),e.getY());
            return true;
        }

        @Override
        public boolean onScroll(@NonNull MotionEvent e1, @NonNull MotionEvent e2, float distanceX, float distanceY) {
            mTranslateX += distanceX;
            mTranslateY += distanceY;
            invalidate();
            return true;
        }
    }
}
